package com.genreate.util.xinyuan;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.genreate.constant.ServiceException;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

/**
 * OSS工具类
 *
 * @author lys
 * @date 2022/11/25
 */
public class HaiwaiOssUtils {
    private static final String endpoint = HaiwaiOssParamEnum.ENDPOINT.getContent();

    private static final String accessKeyId = HaiwaiOssParamEnum.KEY_ID.getContent();

    private static final String accessKeySecret = HaiwaiOssParamEnum.KEY_SECRET.getContent();

    private static final String bucketName = HaiwaiOssParamEnum.BUCKET_NAME.getContent();

    /**
     * 下载url
     */
    private static final String downloadUrl = "https://" + bucketName + "." + endpoint + "/";

    /**
     * 预览url
     */
    private static final String previewUrl = "https://app-oss.shineray-motors.com/";

    /**
     * 上传KD 质量问题 故障件的导入模板
     */
    public static void uploadKdQuesionFault() throws UnsupportedEncodingException {
        //中文 本地路径
        String zhFilePath = "D:\\慧信顺\\鑫源\\海外\\KD\\质量问题_故障件导入_中文.xlsx";
        //英文 本地路径
        String enFilePath = "D:\\慧信顺\\鑫源\\海外\\KD\\质量问题_故障件导入_英文.xlsx";
        //波斯语 本地路径
        String faFilePath = "D:\\慧信顺\\鑫源\\海外\\KD\\质量问题_故障件导入_波斯语.xlsx";
        //俄文 本地路径
        String ruFilePath = "D:\\慧信顺\\鑫源\\海外\\KD\\质量问题_故障件导入_俄文.xlsx";

        //中文 oss路径
        String zhOssPath = "importTemplate/kdQuesionFault/故障配件导入模板.xlsx";
        //英文 oss路径
        String enOssPath = "importTemplate/kdQuesionFault/Template for importing faulty accessories.xlsx";
        //波斯语 oss路径
        String faOssPath = "importTemplate/kdQuesionFault/نمونه برای وارد دسترسی اشتباهی.xlsx";
        //俄文 oss路径
        String ruOssPath = "importTemplate/kdQuesionFault/Шаблон импорта неисправных аксессуаров.xlsx";
        String zhOssPathUpload = fileUpload(zhFilePath, zhOssPath, URLEncoder.encode(FileUtil.getName(zhOssPath), "UTF-8"));
        String enFilePathUpload = fileUpload(enFilePath, enOssPath, URLEncoder.encode(FileUtil.getName(enOssPath), "UTF-8"));
        String faFilePathUpload = fileUpload(faFilePath, faOssPath, URLEncoder.encode(FileUtil.getName(faOssPath), "UTF-8"));
        String ruFilePathUpload = fileUpload(ruFilePath, ruOssPath, URLEncoder.encode(FileUtil.getName(ruOssPath), "UTF-8"));
        System.out.println(StrUtil.format("中文：{}",zhOssPathUpload));
        System.out.println(StrUtil.format("英文：{}",enFilePathUpload));
        System.out.println(StrUtil.format("波斯语：{}",faFilePathUpload));
        System.out.println(StrUtil.format("俄文：{}",ruFilePathUpload));
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        // 本地路径
        String zhFilePath = "D:\\JavaTool\\nginx-1.24.0\\html\\sign\\address.html";

        // oss路径
        String zhOssPath = "importTemplate/forum/signHtml.html";

        String zhOssPathUpload = fileUploadHtml(zhFilePath, zhOssPath);
        System.out.println(StrUtil.format("销售数据：{}",zhOssPathUpload));
    }

    /**
     * 上传销售
     *
     * @throws UnsupportedEncodingException 不支持编码异常
     */
    public static void uploadSale() throws UnsupportedEncodingException {
        // 本地路径
        String zhFilePath = "D:\\慧信顺\\鑫源\\海外\\销售任务\\导入模板\\销售数据导入模板.xlsx";

        // oss路径
        String zhOssPath = "importTemplate/saleTask/销售数据导入模板.xlsx";

        String zhOssPathUpload = fileUpload(zhFilePath, zhOssPath, URLEncoder.encode(FileUtil.getName(zhOssPath), "UTF-8"));
        System.out.println(StrUtil.format("销售数据：{}",zhOssPathUpload));
    }

    /**
     * 得到oss连接
     *
     * @return {@link OSS}
     */
    private static OSS getOssClient() {
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 将文件流上传至阿里云oss
     *
     * @param file        文件流
     * @param ossFilePath 阿里云文件路径 必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     */
    public static String fileUpload(InputStream file, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        ossClient.putObject(bucketName, ossFilePath, file);
        // 关闭OSSClient。
        ossClient.shutdown();
        return getFilePath(ossFilePath);
    }

    /**
     * 将文件流上传至阿里云oss
     *
     * @param file        文件流
     * @param ossFilePath 阿里云文件路径 必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     */
    public static String fileUploadPreview(InputStream file, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        ossClient.putObject(bucketName, ossFilePath, file);
        // 关闭OSSClient。
        ossClient.shutdown();
        return getFilePathPreview(ossFilePath);
    }

    /**
     * 将本地文件上传至阿里云oss 下载模式
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径  必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     */
    public static String fileUpload(String filePath, String ossFilePath, String fileName) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        try {
            InputStream fileInputStream = new FileInputStream(filePath);

            // 创建 ObjectMetadata 对象，用于设置文件元信息
            ObjectMetadata metadata = new ObjectMetadata();
            // 设置 Content-Disposition 响应头，指示浏览器以附件形式下载文件
            metadata.setContentDisposition("attachment; filename=" + fileName);
            // 设置 Content-Type 为 Excel 文件类型
            if (fileName.endsWith(".xlsx")) {
                metadata.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            } else if (fileName.endsWith(".xls")) {
                metadata.setContentType("application/vnd.ms-excel");
            }

            // 创建 PutObjectRequest 对象，包含上传文件的请求信息
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, ossFilePath, fileInputStream, metadata);
            // 上传文件到 OSS
            ossClient.putObject(putObjectRequest);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return getFilePath(ossFilePath);
    }

    /**
     * 将本地文件上传至阿里云oss
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径  必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     */
    public static String fileUpload(String filePath, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        try {
            InputStream fileInputStream = new FileInputStream(filePath);
            ossClient.putObject(bucketName, ossFilePath, fileInputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return getFilePath(ossFilePath);
    }

    /**
     * 将本地文件上传至阿里云oss
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径  必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     */
    public static String fileUploadHtml(String filePath, String ossFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        try {
            InputStream fileInputStream = new FileInputStream(filePath);
            // 1. 创建元数据对象
            ObjectMetadata metadata = new ObjectMetadata();

            // 2. 设置Content-Type为HTML
            metadata.setContentType("text/html");

            // 3. 设置Content-Disposition为inline（预览模式）
            metadata.setContentDisposition("inline; filename=\"" + ossFilePath + "\"");
            ossClient.putObject(bucketName, ossFilePath, fileInputStream, metadata);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return getFilePath(ossFilePath);
    }

    /**
     * 将本地文件上传至阿里云oss
     *
     * @param filePath    本地文件路径
     * @param ossFilePath 阿里云文件路径  必须用  yyyy/MM/dd 格式,用于区分具体某一天上传的文件  最前面可以带上具体的模块名，看功能需求
     * @param isDelFile   是否删除文件
     */
    public static String fileUpload(String filePath, String ossFilePath, boolean isDelFile) {
        try {
            fileUpload(filePath, ossFilePath);
            //本地文件删除
            if (isDelFile) {
                FileUtil.del(filePath);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("oss上传文件出错：" + e.getMessage());
        }
        return getFilePath(ossFilePath);
    }

    /**
     * 获取文件访问地址
     * @param ossPath
     * @return
     */
    public static String getFilePath(String ossPath){
        return  downloadUrl + ossPath;
    }

    /**
     * 预览文件地址
     *
     * @param ossPath 文件路径
     * @return 字符串
     */
    public static String getFilePathPreview(String ossPath){
        return previewUrl + ossPath;
    }

    /**
     * 生成文件下载链接，用于图片不能通过地址拼接访问的方式
     *
     * @param filepath oss文件路径
     * @return {@link String}
     */
    public static String getFileLink(String filepath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, filepath, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return url.toString();
    }

    /**
     * 删除oss一个文件
     *
     * @param ossPath 填写文件完整路径。文件完整路径中不能包含Bucket名称。
     * @return boolean
     */
    public static boolean deleteFileOne(String ossPath) {
        OSS ossClient = getOssClient();
        try {
            ossClient.deleteObject(bucketName, ossPath);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return false;
        } finally {
            Opt.ofNullable(ossClient).ifPresent(e->e.shutdown());
        }
        return true;
    }

    /**
     * 删除oss多个文件
     *
     * @param filePaths 填写需要删除的多个文件完整路径。文件完整路径中不能包含Bucket名称。
     */
    public static void deleteFiles(List<String> filePaths) {
        OSS ossClient = getOssClient();
        try {
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(filePaths).withEncodingType("url"));
            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
            try {
                for (String obj : deletedObjects) {
                    String deleteObj = URLDecoder.decode(obj, "UTF-8");
                    System.out.println(deleteObj);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            Opt.ofNullable(ossClient).ifPresent(e->e.shutdown());
        }
    }

    /**
     * 生成未压缩stream流
     *
     * @param filepath filepath
     * @return {@link InputStream}
     */
    public static InputStream getFileStream(String filepath) {
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();

        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, filepath, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return Opt.ofTry(()-> url.openStream()).exceptionOrElse(null);
    }

}
